package org.sean.framework.canary.loadbalancer.selector;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 轮询
 *
 * @author xielei
 */
@Slf4j
public class RoundRobinSelector {

    private AtomicInteger nextServerCyclicCounter;

    public RoundRobinSelector() {
        nextServerCyclicCounter = new AtomicInteger(0);
    }

    /**
     * 选择其中一个可用服务
     *
     * @param allServers   实例列表
     * @param lastServerId 上次使用实例
     * @return 选中实例
     */
    public ServiceInstance choose(String lastServerId, List<ServiceInstance> allServers) {
        ServiceInstance server = null;
        int count = 0;
        int serverCount = allServers.size();

        while (server == null && count++ < 10) {
            int nextServerIndex = incrementAndGetModulo(serverCount);
            server = allServers.get(nextServerIndex);

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (allServers.size() > 1) {
                if (server.getUri().toString().equals(lastServerId)) {
                    continue;
                }
                return server;
            } else {
                return server;
            }
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries ");
        }
        return server;
    }

    /**
     * 轮询器
     *
     * @param modulo 模
     * @return 下一值
     */
    private int incrementAndGetModulo(int modulo) {
        for (; ; ) {
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;
            if (nextServerCyclicCounter.compareAndSet(current, next)) {
                return next;
            }
        }
    }

}
